Completed
Push — master ( 59ad2d...412337 )
by Xu
293:44 queued 253:04
created

$.fn.extend.slimScroll   D

Complexity

Conditions 20
Paths 46

Size

Total Lines 379

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 20
c 1
b 0
f 0
nc 46
nop 0
dl 0
loc 379
rs 4.7294

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like $.fn.extend.slimScroll often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
/*! Copyright (c) 2011 Piotr Rochala (http://rocha.la)
2
 * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
3
 * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
4
 *
5
 * Version: 1.3.8
6
 *
7
 */
8
(function($) {
9
10
  $.fn.extend({
11
    slimScroll: function(options) {
12
13
      var defaults = {
14
15
        // width in pixels of the visible scroll area
16
        width : 'auto',
17
18
        // height in pixels of the visible scroll area
19
        height : '250px',
20
21
        // width in pixels of the scrollbar and rail
22
        size : '7px',
23
24
        // scrollbar color, accepts any hex/color value
25
        color: '#000',
26
27
        // scrollbar position - left/right
28
        position : 'right',
29
30
        // distance in pixels between the side edge and the scrollbar
31
        distance : '1px',
32
33
        // default scroll position on load - top / bottom / $('selector')
34
        start : 'top',
35
36
        // sets scrollbar opacity
37
        opacity : .4,
38
39
        // enables always-on mode for the scrollbar
40
        alwaysVisible : false,
41
42
        // check if we should hide the scrollbar when user is hovering over
43
        disableFadeOut : false,
44
45
        // sets visibility of the rail
46
        railVisible : false,
47
48
        // sets rail color
49
        railColor : '#333',
50
51
        // sets rail opacity
52
        railOpacity : .2,
53
54
        // whether  we should use jQuery UI Draggable to enable bar dragging
55
        railDraggable : true,
56
57
        // defautlt CSS class of the slimscroll rail
58
        railClass : 'slimScrollRail',
59
60
        // defautlt CSS class of the slimscroll bar
61
        barClass : 'slimScrollBar',
62
63
        // defautlt CSS class of the slimscroll wrapper
64
        wrapperClass : 'slimScrollDiv',
65
66
        // check if mousewheel should scroll the window if we reach top/bottom
67
        allowPageScroll : false,
68
69
        // scroll amount applied to each mouse wheel step
70
        wheelStep : 20,
71
72
        // scroll amount applied when user is using gestures
73
        touchScrollStep : 200,
74
75
        // sets border radius
76
        borderRadius: '7px',
77
78
        // sets border radius of the rail
79
        railBorderRadius : '7px'
80
      };
81
82
      var o = $.extend(defaults, options);
83
84
      // do it for every element that matches selector
85
      this.each(function(){
86
87
      var isOverPanel, isOverBar, isDragg, queueHide, touchDif,
88
        barHeight, percentScroll, lastScroll,
89
        divS = '<div></div>',
90
        minBarHeight = 30,
91
        releaseScroll = false;
92
93
        // used in event handlers and for better minification
94
        var me = $(this);
95
96
        // ensure we are not binding it again
97
        if (me.parent().hasClass(o.wrapperClass))
98
        {
99
            // start from last bar position
100
            var offset = me.scrollTop();
101
102
            // find bar and rail
103
            bar = me.siblings('.' + o.barClass);
104
            rail = me.siblings('.' + o.railClass);
105
106
            getBarHeight();
107
108
            // check if we should scroll existing instance
109
            if ($.isPlainObject(options))
110
            {
111
              // Pass height: auto to an existing slimscroll object to force a resize after contents have changed
112
              if ( 'height' in options && options.height == 'auto' ) {
113
                me.parent().css('height', 'auto');
114
                me.css('height', 'auto');
115
                var height = me.parent().parent().height();
116
                me.parent().css('height', height);
117
                me.css('height', height);
118
              } else if ('height' in options) {
119
                var h = options.height;
120
                me.parent().css('height', h);
121
                me.css('height', h);
122
              }
123
124
              if ('scrollTo' in options)
125
              {
126
                // jump to a static point
127
                offset = parseInt(o.scrollTo);
128
              }
129
              else if ('scrollBy' in options)
130
              {
131
                // jump by value pixels
132
                offset += parseInt(o.scrollBy);
133
              }
134
              else if ('destroy' in options)
135
              {
136
                // remove slimscroll elements
137
                bar.remove();
138
                rail.remove();
139
                me.unwrap();
140
                return;
141
              }
142
143
              // scroll content by the given offset
144
              scrollContent(offset, false, true);
145
            }
146
147
            return;
148
        }
149
        else if ($.isPlainObject(options))
150
        {
151
            if ('destroy' in options)
152
            {
153
            	return;
154
            }
155
        }
156
157
        // optionally set height to the parent's height
158
        o.height = (o.height == 'auto') ? me.parent().height() : o.height;
159
160
        // wrap content
161
        var wrapper = $(divS)
162
          .addClass(o.wrapperClass)
163
          .css({
164
            position: 'relative',
165
            overflow: 'hidden',
166
            width: o.width,
167
            height: o.height
168
          });
169
170
        // update style for the div
171
        me.css({
172
          overflow: 'hidden',
173
          width: o.width,
174
          height: o.height
175
        });
176
177
        // create scrollbar rail
178
        var rail = $(divS)
179
          .addClass(o.railClass)
180
          .css({
181
            width: o.size,
182
            height: '100%',
183
            position: 'absolute',
184
            top: 0,
185
            display: (o.alwaysVisible && o.railVisible) ? 'block' : 'none',
186
            'border-radius': o.railBorderRadius,
187
            background: o.railColor,
188
            opacity: o.railOpacity,
189
            zIndex: 90
190
          });
191
192
        // create scrollbar
193
        var bar = $(divS)
194
          .addClass(o.barClass)
195
          .css({
196
            background: o.color,
197
            width: o.size,
198
            position: 'absolute',
199
            top: 0,
200
            opacity: o.opacity,
201
            display: o.alwaysVisible ? 'block' : 'none',
202
            'border-radius' : o.borderRadius,
203
            BorderRadius: o.borderRadius,
204
            MozBorderRadius: o.borderRadius,
205
            WebkitBorderRadius: o.borderRadius,
206
            zIndex: 99
207
          });
208
209
        // set position
210
        var posCss = (o.position == 'right') ? { right: o.distance } : { left: o.distance };
211
        rail.css(posCss);
212
        bar.css(posCss);
213
214
        // wrap it
215
        me.wrap(wrapper);
216
217
        // append to parent div
218
        me.parent().append(bar);
219
        me.parent().append(rail);
220
221
        // make it draggable and no longer dependent on the jqueryUI
222
        if (o.railDraggable){
223
          bar.bind("mousedown", function(e) {
224
            var $doc = $(document);
225
            isDragg = true;
226
            t = parseFloat(bar.css('top'));
0 ignored issues
show
Bug introduced by
The variable t seems to be never declared. Assigning variables without defining them first makes them global. If this was intended, consider making it explicit like using window.t.
Loading history...
227
            pageY = e.pageY;
0 ignored issues
show
Bug introduced by
The variable pageY seems to be never declared. Assigning variables without defining them first makes them global. If this was intended, consider making it explicit like using window.pageY.
Loading history...
228
229
            $doc.bind("mousemove.slimscroll", function(e){
230
              currTop = t + e.pageY - pageY;
0 ignored issues
show
Bug introduced by
The variable currTop seems to be never declared. Assigning variables without defining them first makes them global. If this was intended, consider making it explicit like using window.currTop.
Loading history...
231
              bar.css('top', currTop);
232
              scrollContent(0, bar.position().top, false);// scroll content
233
            });
234
235
            $doc.bind("mouseup.slimscroll", function(e) {
0 ignored issues
show
Unused Code introduced by
The parameter e is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
236
              isDragg = false;hideBar();
237
              $doc.unbind('.slimscroll');
238
            });
239
            return false;
240
          }).bind("selectstart.slimscroll", function(e){
241
            e.stopPropagation();
242
            e.preventDefault();
243
            return false;
244
          });
245
        }
246
247
        // on rail over
248
        rail.hover(function(){
249
          showBar();
250
        }, function(){
251
          hideBar();
252
        });
253
254
        // on bar over
255
        bar.hover(function(){
256
          isOverBar = true;
257
        }, function(){
258
          isOverBar = false;
259
        });
260
261
        // show on parent mouseover
262
        me.hover(function(){
263
          isOverPanel = true;
264
          showBar();
265
          hideBar();
266
        }, function(){
267
          isOverPanel = false;
268
          hideBar();
269
        });
270
271
        // support for mobile
272
        me.bind('touchstart', function(e,b){
0 ignored issues
show
Unused Code introduced by
The parameter b is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
273
          if (e.originalEvent.touches.length)
274
          {
275
            // record where touch started
276
            touchDif = e.originalEvent.touches[0].pageY;
277
          }
278
        });
279
280
        me.bind('touchmove', function(e){
281
          // prevent scrolling the page if necessary
282
          if(!releaseScroll)
283
          {
284
  		      e.originalEvent.preventDefault();
285
		      }
286
          if (e.originalEvent.touches.length)
287
          {
288
            // see how far user swiped
289
            var diff = (touchDif - e.originalEvent.touches[0].pageY) / o.touchScrollStep;
290
            // scroll content
291
            scrollContent(diff, true);
292
            touchDif = e.originalEvent.touches[0].pageY;
293
          }
294
        });
295
296
        // set up initial height
297
        getBarHeight();
298
299
        // check start position
300
        if (o.start === 'bottom')
301
        {
302
          // scroll content to bottom
303
          bar.css({ top: me.outerHeight() - bar.outerHeight() });
304
          scrollContent(0, true);
305
        }
306
        else if (o.start !== 'top')
307
        {
308
          // assume jQuery selector
309
          scrollContent($(o.start).position().top, null, true);
310
311
          // make sure bar stays hidden
312
          if (!o.alwaysVisible) { bar.hide(); }
313
        }
314
315
        // attach scroll events
316
        attachWheel(this);
317
318
        function _onWheel(e)
319
        {
320
          // use mouse wheel only when mouse is over
321
          if (!isOverPanel) { return; }
322
323
          var e = e || window.event;
324
325
          var delta = 0;
326
          if (e.wheelDelta) { delta = -e.wheelDelta/120; }
327
          if (e.detail) { delta = e.detail / 3; }
328
329
          var target = e.target || e.srcTarget || e.srcElement;
330
          if ($(target).closest('.' + o.wrapperClass).is(me.parent())) {
331
            // scroll content
332
            scrollContent(delta, true);
333
          }
334
335
          // stop window scroll
336
          if (e.preventDefault && !releaseScroll) { e.preventDefault(); }
337
          if (!releaseScroll) { e.returnValue = false; }
338
        }
339
340
        function scrollContent(y, isWheel, isJump)
341
        {
342
          releaseScroll = false;
343
          var delta = y;
0 ignored issues
show
Unused Code introduced by
The assignment to variable delta seems to be never used. Consider removing it.
Loading history...
344
          var maxTop = me.outerHeight() - bar.outerHeight();
345
346
          if (isWheel)
347
          {
348
            // move bar with mouse wheel
349
            delta = parseInt(bar.css('top')) + y * parseInt(o.wheelStep) / 100 * bar.outerHeight();
350
351
            // move bar, make sure it doesn't go out
352
            delta = Math.min(Math.max(delta, 0), maxTop);
353
354
            // if scrolling down, make sure a fractional change to the
355
            // scroll position isn't rounded away when the scrollbar's CSS is set
356
            // this flooring of delta would happened automatically when
357
            // bar.css is set below, but we floor here for clarity
358
            delta = (y > 0) ? Math.ceil(delta) : Math.floor(delta);
359
360
            // scroll the scrollbar
361
            bar.css({ top: delta + 'px' });
362
          }
363
364
          // calculate actual scroll amount
365
          percentScroll = parseInt(bar.css('top')) / (me.outerHeight() - bar.outerHeight());
366
          delta = percentScroll * (me[0].scrollHeight - me.outerHeight());
367
368
          if (isJump)
369
          {
370
            delta = y;
371
            var offsetTop = delta / me[0].scrollHeight * me.outerHeight();
372
            offsetTop = Math.min(Math.max(offsetTop, 0), maxTop);
373
            bar.css({ top: offsetTop + 'px' });
374
          }
375
376
          // scroll content
377
          me.scrollTop(delta);
378
379
          // fire scrolling event
380
          me.trigger('slimscrolling', ~~delta);
381
382
          // ensure bar is visible
383
          showBar();
384
385
          // trigger hide when scroll is stopped
386
          hideBar();
387
        }
388
389
        function attachWheel(target)
390
        {
391
          if (window.addEventListener)
392
          {
393
            target.addEventListener('DOMMouseScroll', _onWheel, false );
394
            target.addEventListener('mousewheel', _onWheel, false );
395
          }
396
          else
397
          {
398
            document.attachEvent("onmousewheel", _onWheel)
399
          }
400
        }
401
402
        function getBarHeight()
403
        {
404
          // calculate scrollbar height and make sure it is not too small
405
          barHeight = Math.max((me.outerHeight() / me[0].scrollHeight) * me.outerHeight(), minBarHeight);
406
          bar.css({ height: barHeight + 'px' });
407
408
          // hide scrollbar if content is not long enough
409
          var display = barHeight == me.outerHeight() ? 'none' : 'block';
410
          bar.css({ display: display });
411
        }
412
413
        function showBar()
414
        {
415
          // recalculate bar height
416
          getBarHeight();
417
          clearTimeout(queueHide);
418
419
          // when bar reached top or bottom
420
          if (percentScroll == ~~percentScroll)
421
          {
422
            //release wheel
423
            releaseScroll = o.allowPageScroll;
424
425
            // publish approporiate event
426
            if (lastScroll != percentScroll)
427
            {
428
                var msg = (~~percentScroll == 0) ? 'top' : 'bottom';
429
                me.trigger('slimscroll', msg);
430
            }
431
          }
432
          else
433
          {
434
            releaseScroll = false;
435
          }
436
          lastScroll = percentScroll;
437
438
          // show only when required
439
          if(barHeight >= me.outerHeight()) {
440
            //allow window scroll
441
            releaseScroll = true;
442
            return;
443
          }
444
          bar.stop(true,true).fadeIn('fast');
445
          if (o.railVisible) { rail.stop(true,true).fadeIn('fast'); }
446
        }
447
448
        function hideBar()
449
        {
450
          // only hide when options allow it
451
          if (!o.alwaysVisible)
452
          {
453
            queueHide = setTimeout(function(){
454
              if (!(o.disableFadeOut && isOverPanel) && !isOverBar && !isDragg)
455
              {
456
                bar.fadeOut('slow');
457
                rail.fadeOut('slow');
458
              }
459
            }, 1000);
460
          }
461
        }
462
463
      });
464
465
      // maintain chainability
466
      return this;
467
    }
468
  });
469
470
  $.fn.extend({
471
    slimscroll: $.fn.slimScroll
472
  });
473
474
})(jQuery);
475